import os from "os";
import chalk from "chalk";
const { cyan, green, bold } = chalk;
import type { Compiler } from "webpack";

type ClientPluginOptions = {
  publicPath: string;
  enable?: boolean; // 是否启用输出（默认仅 TTY 下启用）
  reprintOnChange?: boolean; // host/port/base 变化是否重印（默认 true）
  reprintOnRecover?: boolean; // 编译失败后首次成功是否重印（默认 true）
};

class ClientPlugin {
  publicPath: string;
  private hasPrinted: boolean;
  private lastSignature?: string;
  private enabled: boolean;
  private reprintOnChange: boolean;
  private reprintOnRecover: boolean;
  private lastFailed: boolean;
  constructor(opts: string | ClientPluginOptions) {
    if (typeof opts === 'string') {
      this.publicPath = opts;
      this.enabled = !!process.stdout.isTTY;
      this.reprintOnChange = true;
      this.reprintOnRecover = true;
    } else {
      this.publicPath = opts.publicPath;
      this.enabled = opts.enable ?? !!process.stdout.isTTY;
      this.reprintOnChange = opts.reprintOnChange ?? true;
      this.reprintOnRecover = opts.reprintOnRecover ?? true;
    }
    this.hasPrinted = false;
    this.lastFailed = false;
  }
  apply(compiler: Compiler) {
    compiler.hooks.failed.tap('ClientPlugin', () => {
      this.lastFailed = true;
    });
    compiler.hooks.done.tap('ClientPlugin', (stats) => {
      if (!this.enabled) return;
      const devServer = stats.compilation.options.devServer as any || {};
      const port = devServer?.port ?? 8080;
      const host = devServer?.host ?? 'localhost';
      const server = devServer?.server ?? {};
      const outputPublicPath = (stats.compilation.outputOptions.publicPath as any) || '/';
      const normalizeBase = (basePath: string) => {
        if (!basePath) return "/";
        if (basePath === 'auto') return basePath;
        if (/^https?:\/\//i.test(basePath)) return basePath.endsWith('/') ? basePath : basePath + '/';
        const withLead = basePath.startsWith('/') ? basePath : '/' + basePath;
        return withLead.endsWith('/') ? withLead : withLead + '/';
      };
      const basePath = normalizeBase(this.publicPath || outputPublicPath || '/');
      const networkInterfaces = os.networkInterfaces();
      let protocol = "http";
      let localLabelHost = host === '0.0.0.0' || host === '::' ? 'localhost' : host;
      let lanIP = '';
      if (Object.prototype.toString.call(server) === "[object String]") {
        if (server && server.toLowerCase() === "https") {
          protocol = "https";
        }
      } else {
        if (server.type && server.type.toLowerCase() === "https") {
          protocol = "https";
        }
      }
      for (const iface of Object.values(networkInterfaces)) {
        if (iface) {
          for (const config of iface) {
            if (config.family === 'IPv4' && !config.internal) {
              lanIP = config.address;
            }
          }
        }
      }
      const localUrl = `${protocol}://${localLabelHost}:${port}${basePath}`;
      const networkUrl = lanIP ? `${protocol}://${lanIP}:${port}${basePath}` : '';
      const signature = `${protocol}://${host}:${port}${basePath}`;
      const shouldReprintByChange = this.reprintOnChange && this.lastSignature !== undefined && this.lastSignature !== signature;
      const shouldReprintByRecover = this.reprintOnRecover && this.lastFailed;
      if (!this.hasPrinted || shouldReprintByChange || shouldReprintByRecover) {
        console.log(`${bold(green("➜ Local: "))}${cyan(localUrl)}`);
        if (networkUrl) {
          console.log(`${bold(green("➜ Network: "))}${cyan(`${networkUrl}\n`)}`);
        } else {
          console.log();
        }
        this.hasPrinted = true;
        this.lastSignature = signature;
        this.lastFailed = false;
      }
    });
  }
}

export default ClientPlugin;